/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "StdAfx.h"
#include "ScriptingEngineLua.h"
#include "core/core.h"

extern "C" {
	#include "lauxlib.h"
	#include "lualib.h"

	#include <stdarg.h>
	#include <stdio.h>
	#include <stdlib.h>
}

#include <sstream>

ScriptingEngineLua *g_pScriptEng = NULL;

bool coreInitScriptingEngineLua() 
{	
	g_pScriptEng = new ScriptingEngineLua();
	coreAddModule(g_pScriptEng);
	return true;
}

ScriptingEngineLua* coreGetScriptingEngineLua()
{
	return g_pScriptEng;
}

std::string concatStrChar(const std::string &str1, const char* str2)
{
	std::stringstream sstr;
	sstr << str1 << str2;
	std::string retStr = sstr.str();
	sstr.str("");
	sstr.clear();
	return retStr;
}

ScriptingEngineLua::ScriptingEngineLua(void)
{	
}

ScriptingEngineLua::~ScriptingEngineLua(void)
{
}

void ScriptingEngineLua::Destroy()
{
	DELETE_POINTER(g_pScriptEng);
}

bool ScriptingEngineLua::readFile(lua_State* L, const char* fileName)
{
	lua_settop(L,0);
	//STRINGCOUT("ScriptingEngine::readFile: " << fileName);
	if(luaL_loadfile(L, fileName) || lua_pcall(L, 0, 1, 0)) {
		coreGetLog()->WriteLuaError(concatStrChar("Lua_State could not open file: ", fileName), __FILE__, __LINE__);		
		coreGetLog()->WriteLuaError(concatStrChar("Lua Error: ", lua_tostring(L, -1)), __FILE__, __LINE__ );	
		STDCOUT(lua_tostring(L, -1));
		lua_settop(L,0);
		return false;
	}
	return true;
}

bool ScriptingEngineLua::writeTableToFile(lua_State* L, const char* tableName, const char* fileName){
	
	// lege Funktionen und Argumente auf den Stack
	lua_getglobal(L, "schreibeTabelle");
	lua_getglobal(L, tableName);
	lua_pushstring(L, tableName);
	lua_pushstring(L, fileName);

	// rufe Funktion auf (3 Argumente, 1 Ergebnisse)
	if (lua_pcall(L, 3, 0, 0) != 0){
		coreGetLog()->WriteLuaError(concatStrChar("Can't write table: ", tableName), __FILE__, __LINE__);
		coreGetLog()->WriteLuaError(concatStrChar("Lua Error: ", lua_tostring(L, -1)), __FILE__, __LINE__ );	
		lua_pop(L,1);
		return false;
	}
	return true;
}

bool ScriptingEngineLua::isTableValue(lua_State *L, const char* tableName, const char* key){
	lua_getglobal(L, tableName);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tableName), __FILE__, __LINE__);
//		error("%s %s", tableName, " is not a table");
	}	
	
	lua_pushstring(L, key);
	lua_gettable(L, -2); // hole Background[key]
	if (lua_isnil(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Can't write table: ", tableName), __FILE__, __LINE__);
		//error("%s %s", "Value %s does not exist in table %s ", key, tableName);
		return false;
	}
	
	lua_pop(L, 2); // entferne Key und Tabelle
	return true;
}

lua_Number ScriptingEngineLua::getFieldNum(lua_State* L, const char *tablename, const char *key){
	
	lua_getglobal(L, tablename);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tablename), __FILE__, __LINE__);
		//error("%s %s", tablename, " is not a table");
	}	
	
	lua_Number result;
	lua_pushstring(L, key);
	lua_gettable(L, -2); // hole Background[key]
	if (!lua_isnumber(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Invalid value in Field: ", key), __FILE__, __LINE__);
		//error("%S %S", "invalid value in getFieldNum ", key);
	}
	result = lua_tonumber(L, -1); 
	lua_pop(L, 2); // entferne Zahl und Tabelle
	return result;
}

const char* ScriptingEngineLua::getFieldString(lua_State* L, const char *tablename, const char *key){
	
	lua_getglobal(L, tablename);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tablename), __FILE__, __LINE__);
		//error("%s %s", tablename, " is not a table");
	}	
	
	const char* result;
	lua_pushstring(L, key);
	lua_gettable(L, -2); // hole Background[key]
	if (!lua_isstring(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Invalid value in getFieldString key: ", key), __FILE__, __LINE__);
		//error("%s %s ", "invalid value in getFieldString ", key);
	}
	result = lua_tostring(L, -1); 
	lua_pop(L, 2); // entferne Zahl und Tabelle
	return result;
}

bool ScriptingEngineLua::getFieldBool(lua_State* L, const char *tablename, const char *key){
	
	lua_getglobal(L, tablename);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tablename), __FILE__, __LINE__);
		//error("%s %s", tablename, " is not a table");
	}	
	
	bool result;
	lua_pushstring(L, key);
	lua_gettable(L, -2); // hole Background[key]
	if (!lua_isboolean(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Invalid value in getFieldBool(): ", key), __FILE__, __LINE__);
		//error("%s %s", "invalid value in getFieldBool() ", key);
	}
	result = lua_toboolean(L, -1) != 0;
	lua_pop(L, 2); // entferne Zahl und Tabelle
	return result;
}

std::string ScriptingEngineLua::processCommand(lua_State *L, const std::string &inputLine) 
{
	int error;
	std::string errorString;
	
	error = luaL_loadbuffer(L, inputLine.c_str(), inputLine.length(), "line") ||
			lua_pcall(L,0,0,0);
	
	if (error){
		errorString = lua_tostring(L, -1);
		lua_pop(L, 1);
	}else{
		errorString = "";
	}

	return errorString;
}

void ScriptingEngineLua::setFieldNum(lua_State* L, const char* tableName, const char* key, lua_Number val){
	lua_getglobal(L, tableName);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tableName), __FILE__, __LINE__);
		//error("%s %s", tableName, " is not a table");
	}
	
	lua_pushstring(L, key);
	lua_pushnumber(L, val);
	lua_settable(L, -3);

	lua_pop(L, 1);
}


void ScriptingEngineLua::setFieldString(lua_State* L, const char* tableName, const char* key, std::string val){
	lua_getglobal(L, tableName);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tableName), __FILE__, __LINE__);
		//error("%s %s", tableName, " is not a table");
	}
	
	lua_pushstring(L, key);
	lua_pushstring(L, val.c_str());
	lua_settable(L, -3);

	lua_pop(L, 1);
}



void ScriptingEngineLua::setFieldBool(lua_State* L, const char* tableName, const char* key, bool val){
	lua_getglobal(L, tableName);
	if (!lua_istable(L, -1)){
		coreGetLog()->WriteLuaError(concatStrChar("Is not a table: ", tableName), __FILE__, __LINE__);
		//error("%s %s", tableName, " is not a table");
	}
	
	lua_pushstring(L, key);
	lua_pushboolean(L, val);
	lua_settable(L, -3);

	lua_pop(L, 1);
}

void ScriptingEngineLua::error(const char *fmt, ...){
	va_list argp;
	va_start(argp, fmt);
	vfprintf(stderr, fmt, argp);
	va_end(argp);

	STRINGCOUT("Error!");
	//lua_close(L); Close the corresponding Lua-State
	exit(EXIT_FAILURE);
}

